﻿

namespace Patterns4Net.ArchitectureExplorer.Infrastructure.Config
{
    using System.ComponentModel.Composition;
    using System.IO;
    using System.Xml;
    using System.Xml.Serialization;

    /// <summary>
    /// Serializes or deserializes settings into or from an xml file.
    /// </summary>
    [Export(typeof(ISettingsSerializer))]
    [PartCreationPolicy(CreationPolicy.Shared)]
    public class SettingsSerializer : ISettingsSerializer
    {
        /// <summary>
        /// Loads settings from given file.
        /// </summary>
        /// <remarks>It does not handle any exceptions.</remarks>
        public Settings Load(string filename)
        {
            var config = GetConfig(filename);
            var result = new Settings();

            result.IgnoredNamespaces.Clear();
            foreach (var @namespace in config.ignorenamespaces)
            {
                result.IgnoredNamespaces.Add(@namespace);
            }

            result.IgnoredTypes.Clear();
            foreach (var type in config.ignoretypes)
            {
                result.IgnoredTypes.Add(type);
            }

            result.IgnoredMembers.Clear();
            foreach (var member in config.ignoremembers)
            {
                result.IgnoredMembers.Add(member);
            }

            result.AdditionalGraphAttributes.Clear();
            foreach (var attribute in config.dot.graphattributes)
            {
                result.AdditionalGraphAttributes.Add(attribute.name, attribute.value);
            }

            return result;
        }

        /// <summary>
        /// Saves settings to given file.
        /// </summary>
        /// <remarks>It does not handle any exceptions.</remarks>
        public void Save(Settings settings, string filename)
        {
            var original = new ArchitectureExplorerConfig();
            try
            {
                // we will try to load the original, and overwrite it's Architecture Explorer specific values...
                original = GetConfig(filename);
            }
            catch
            {
                // if we cant load it, it will be overriden/created...
            }

            original.ignorenamespaces = new string[settings.IgnoredNamespaces.Count];
            int i = 0;
            foreach (var @namespace in settings.IgnoredNamespaces)
            {
                original.ignorenamespaces[i++] = @namespace;
            }

            original.ignoretypes = new string[settings.IgnoredTypes.Count];
            i = 0;
            foreach (var type in settings.IgnoredTypes)
            {
                original.ignoretypes[i++] =type;
            }

            original.ignoremembers = new string[settings.IgnoredMembers.Count];
            i = 0;
            foreach (var member in settings.IgnoredMembers)
            {
                original.ignoremembers[i++] = member;
            }

            original.dot.graphattributes = new DotAttributesListAttribute[settings.AdditionalGraphAttributes.Count];
            i = 0;
            foreach (var attribute in settings.AdditionalGraphAttributes)
            {
                original.dot.graphattributes[i++] = new DotAttributesListAttribute
                                                      {
                                                          name = attribute.Key,
                                                          value = attribute.Value
                                                      };
            }

            using (var writer = new XmlTextWriter(new StreamWriter(filename, append: false)))
            {
                var serializer = new XmlSerializer(typeof(ArchitectureExplorerConfig));
                serializer.Serialize(writer, original);
            }
        }

        private static ArchitectureExplorerConfig GetConfig(string filename)
        {
            using (var reader = new XmlTextReader(new StreamReader(filename)))
            {
                var serializer = new XmlSerializer(typeof(ArchitectureExplorerConfig));
                var result = serializer.Deserialize(reader);
                return (ArchitectureExplorerConfig)result;
            }
        }
    }
}
